import { tableCellType } from './TableCellType';
import { gkhCreate, RecordOperation } from './tools';

function GkhContainer(node, mode, parentComponent) {
    const me = this;
    this.parentComponent = parentComponent;
    this.name = 'gkhContainer';
    this.type = 2; // 1:table  2:word
    let className = mode === 1 ? ' gkh-childs-border' : '';
    className = className.concat(' gkh'.concat(new Date().getTime().toString()).concat(Math.floor(Math.random() * 10000).toString()));
    const container = gkhCreate('div', {
        className: 'gkh-container'.concat(className),
    });
    let parentNode = node;
    let idCount = 0;
    let childInfos = [];
    let dataIndex = 0;
    let containerInfo = {};
    let groupInfos = {};
    let groupComponents = {};
    // 选取元素的时候画的框
    let selectBox;
    // 操作记录
    const handleRecord = new RecordOperation(20);
    this.record = handleRecord;
    function findChildNode(node) {
        let n = node.parentNode;
        let m = node;
        if (node.className && node.className.indexOf(className) > -1) {
            return null;
        }
        for (let i = 0; i < 20; i += 1) {
            if (n) {
                if (n.className && n.className.indexOf(className) > -1) {
                    return m;
                }
                m = n;
                n = n.parentNode;
            } else {
                break;
            }
        }
        return null;
    }

    if (mode == 1) {
        selectBox = gkhCreate('div', {
            style: {
                position: 'absolute',
                display: 'none',
                border: '1px dashed #e5f8fd'
            }
        })
        container.ondragover = function (event) {
            event.preventDefault();
            event.stopPropagation();
            event.cancelBubble = true;
            return false;
        }
        container.ondrop = function (event) {
            event.preventDefault();
            var data = event.dataTransfer.getData("gkhWordCellId");
            event.dataTransfer.setData("gkhWordCellId", undefined);
            if (data) {
                addItemByComponent(tableCellType(me, mode, { type: parseInt(data) }), {});
            }
            event.stopPropagation();
            event.cancelBubble = true;
            return false;
        }
    }

    function getNodeInfo(ele) {
        const { screenX, screenY } = window;
        const { x, y, top, left, bottom, right, width, height } = ele.getBoundingClientRect();
        return {
            x: x + screenX,
            left: left + screenX,
            right: right + screenX,
            y: y + screenY,
            top: top + screenY,
            bottom: bottom + screenY,
            width,
            height,
        }
    }

    function getWordItemData(item) {
        const { node, component } = item;
        const { borderWidth, borderStyle, borderColor, backgroundColor, color, fontFamily, fontSize, lineHeight, fontWeight, left, top, position, textAlign, zIndex, margin, padding } = window.getComputedStyle(node);
        const family = fontFamily.length < 20 ? fontFamily : undefined;
        let nodeHeight = node.offsetHeight;
        if (component.attrData.type == 3) { // 表格减掉编辑头的高度
            nodeHeight -= 28;
        }
        return [component.getAttrData(), (node.offsetWidth / wordWidth).toFixed(4), nodeHeight, borderWidth, borderStyle, borderColor, backgroundColor, color, family, fontSize, lineHeight, fontWeight, left, top, position, textAlign, zIndex, margin, padding];
    }
    // 获取文档模板数据
    function getTempData() {
        const { borderWidth, borderStyle, borderColor, backgroundColor, color, fontFamily, fontSize, lineHeight, fontWeight, margin, padding, paddingLeft, paddingRight } = window.getComputedStyle(container);
        const { width, height } = getNodeInfo(container);
        let family = fontFamily.length < 20 ? fontFamily : undefined;
        wordWidth = width - 2 * parseInt(borderWidth) - parseInt(paddingLeft) - parseInt(paddingRight);
        return [
            [height, borderWidth, borderStyle, borderColor, backgroundColor, color, family, fontSize, lineHeight, fontWeight, margin, padding],
            childInfos.map(getWordItemData)
        ];
    }

    function itemChange(arg) {
        hasChange = false;
        containerInfo = getNodeInfo(container);
        for (let i = 0; i < childInfos.length; i += 1) {
            childInfos[i].info = getNodeInfo(childInfos[i].node);
            if (childInfos[i].component.sizeChange) {
                childInfos[i].component.sizeChange();
            }
        }
        if (!arg) {
            const data = getTempData();
            handleRecord.push(data);
        }
    }

    let changeItem;
    let mouseDown = false;
    let downPoint;
    let positionPoint;
    let hasChange = false;
    let handle = 0; // 1:移动盒子 2：改变盒子宽度向右 3：改变盒子高度向下 4：改变盒子宽度向左 5：改变盒子高度向上
    let round;
    let parentNodeInfo;
    let nodeClassName;
    let selectItem;
    let valueHandle;
    const precision = 5;
    let selectedCells = [];
    let selectedCellsBack = [];
    const selectClassName = " gkh_selected";
    let wordWidth = 0;

    function clearSelectedCells() {
        let className;
        selectedCells.forEach(item => {
            className = item.node.getAttribute('class');
            item.node.setAttribute('class', className.replace(selectClassName, ''));
        });
        selectedCellsBack = selectedCells;
        selectedCells = [];
    }

    function onMouseDown(e) {
        mouseDown = true;
        const { screenX, screenY } = window;
        downPoint = {
            x: e.clientX + screenX,
            y: e.clientY + screenY
        };
        if (selectItem) {
            selectItem.node.setAttribute('class', nodeClassName);
            selectItem = undefined;
        }
        clearSelectedCells();
        me.selectedNode = changeItem;
        if (changeItem) {
            selectItem = changeItem;
            const { node, component } = changeItem;
            if (me.selectedCellChange) {
                me.selectedCellChange(window.getComputedStyle(node), component, me);
            }
            nodeClassName = node.getAttribute('class');
            const className = nodeClassName ? nodeClassName.concat(' gkh-focus') : 'gkh-focus';
            node.setAttribute('class', className);
            parentNodeInfo = getNodeInfo(container);
            const { left, right, top, bottom, width, height } = parentNodeInfo;
            changeItem.info = getNodeInfo(node);
            const pleft = node.style.left ? parseFloat(node.style.left) : 0;
            const ptop = node.style.top ? parseFloat(node.style.top) : 0;
            positionPoint = {
                x: changeItem.info.x - pleft,
                y: changeItem.info.y - ptop,
            }
            round = {
                minX: left - positionPoint.x,
                maxX: left - positionPoint.x + width - changeItem.info.width,
                minY: top - positionPoint.y,
                maxY: top - positionPoint.y + height - changeItem.info.height
            }
            if (handle === 1 || (handle > 5 && handle < 9)) {
                node.style.position = 'absolute';
            }
        } else {
            if (me.selectedCellChange) {
                me.selectedCellChange(window.getComputedStyle(e.target), undefined, me);
            }
            selectBox.style.display = 'block';
        }
        e.stopPropagation();
        e.cancelBubble = true;
        return false;
    }

    function childNodeSelectedChange(style, component, template) {
        if (me.selectedCellChange) {
            me.selectedCellChange(style, component, template);
        }
    }

    function onMouseMove(e) {
        const { screenX, screenY } = window;
        const clientX = screenX + e.clientX;
        const clientY = screenY + e.clientY;
        // console.log(e)
        // console.log(clientX,clientY,e.screenX,e.screenY-clientY)
        if (mouseDown) {
            if (changeItem) {
                const { node, info: { width, height, x, y } } = changeItem;
                switch (handle) {
                    case 1: {
                        const dx = clientX - positionPoint.x;
                        const dy = clientY - positionPoint.y;
                        if (round.minX < dx && dx < round.maxX && round.minY < dy && dy < round.maxY) {
                            node.style.left = dx.toString().concat('px');
                            node.style.top = dy.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 6: {
                        const dx = clientX - width - positionPoint.x;
                        const dy = clientY - positionPoint.y;
                        if (round.minX < dx && dx < round.maxX && round.minY < dy && dy < round.maxY) {
                            node.style.left = dx.toString().concat('px');
                            node.style.top = dy.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 7: {
                        const dx = clientX - positionPoint.x;
                        const dy = clientY - height - positionPoint.y;
                        if (round.minX < dx && dx < round.maxX && round.minY < dy && dy < round.maxY) {
                            node.style.left = dx.toString().concat('px');
                            node.style.top = dy.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 8: {
                        const dx = clientX - width - positionPoint.x;
                        const dy = clientY - height - positionPoint.y;
                        if (round.minX < dx && dx < round.maxX && round.minY < dy && dy < round.maxY) {
                            node.style.left = dx.toString().concat('px');
                            node.style.top = dy.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 2: {
                        const dw = width + clientX - downPoint.x;
                        if (dw > 0 && dw < parentNodeInfo.width) {
                            node.style.width = dw.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 3: {
                        const dh = height + clientY - downPoint.y;
                        if (dh > 0 && dh < parentNodeInfo.height) {
                            node.style.minHeight = dh.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 4: {
                        const dx = x - parentNodeInfo.x + clientX - downPoint.x;
                        const dw = width + downPoint.x - clientX;
                        if (dw > 0 && dw < parentNodeInfo.width) {
                            node.style.left = dx.toString().concat('px');
                            node.style.width = dw.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                    case 5: {
                        const dy = y - parentNodeInfo.y + clientY - downPoint.y;
                        const dh = height + downPoint.y - clientY;
                        if (dh > 0 && dh < parentNodeInfo.height) {
                            node.style.top = dy.toString().concat('px');
                            node.style.minHeight = dh.toString().concat('px');
                        }
                        hasChange = true;
                    } break;
                }
            }
            if (!handle) { // 选取单元
                clearSelectedCells();
                let pleft = 0;
                let ptop = 0;
                let pright = 0;
                let pbottom = 0;
                if (clientX - downPoint.x > 0) {
                    pleft = downPoint.x;
                    pright = clientX;
                } else {
                    pleft = clientX;
                    pright = downPoint.x;
                }
                if (clientY - downPoint.y > 0) {
                    ptop = downPoint.y;
                    pbottom = clientY;
                } else {
                    ptop = clientY;
                    pbottom = downPoint.y;
                }
                selectBox.style.left = (pleft - containerInfo.left).toString().concat('px');
                selectBox.style.top = (ptop - containerInfo.top).toString().concat('px');
                selectBox.style.width = (pright - pleft).toString().concat('px');
                selectBox.style.height = (pbottom - ptop).toString().concat('px');
                let className;
                childInfos.forEach(item => {
                    const { left, top, right, bottom } = item.info;
                    if (right > pleft && bottom > ptop && left < pright && top < pbottom) {
                        className = item.node.getAttribute('class');
                        className = className ? className.concat(selectClassName) : selectClassName;
                        item.node.setAttribute('class', className);
                        selectedCells.push(item);
                    }
                });
                selectedCellsBack = selectedCells;
            }
        } else {
            let className = container.getAttribute('class');
            className = className ? className : '';
            className = className.replace(' gkh-box-move', '');
            className = className.replace(' gkh-box-eresize', '');
            className = className.replace(' gkh-box-nresize', '');
            handle = 0;
            const target = findChildNode(e.target);
            changeItem = undefined;
            if (target && target.info) {
                changeItem = target.info;
                const { info: { left, right, top, bottom } } = changeItem;
                // 触发移动标识
                if (clientX - left < precision && clientX > left && clientY > top && clientY - top < precision) {
                    className = className.concat(' gkh-box-move');
                    handle = 1;
                } else if (right - clientX < precision && clientX < right && clientY > top && clientY - top < precision) {
                    className = className.concat(' gkh-box-move');
                    handle = 6;
                } else if (clientX - left < precision && clientX > left && clientY < bottom && bottom - clientY < precision) {
                    className = className.concat(' gkh-box-move');
                    handle = 7;
                } else if (right - clientX < precision && clientX < right && clientY < bottom && bottom - clientY < precision) {
                    className = className.concat(' gkh-box-move');
                    handle = 8;
                } else if (right - clientX < precision && right > clientX) { // 触发宽度修改标识 向右
                    className = className.concat(' gkh-box-eresize');
                    handle = 2;
                } else if (bottom - clientY < precision && bottom > clientY) { // 触发高度修改标识 向下
                    className = className.concat(' gkh-box-nresize');
                    handle = 3;
                } else if (clientX - left < precision && left < clientX) { // 触发宽度修改标识 向左
                    className = className.concat(' gkh-box-eresize');
                    handle = 4;
                } else if (clientY - top < precision && top < clientY) { // 触发高度修改标识 向上
                    className = className.concat(' gkh-box-nresize');
                    handle = 5;
                }
            }
            container.setAttribute('class', className);
        }
        e.stopPropagation();
        e.cancelBubble = true;
        return false;
    }

    function onMouseUp() {
        mouseDown = false;
        if (hasChange) {
            itemChange();
        }
        if (selectBox) {
            selectBox.style.display = 'none';
            selectBox.style.width = 0;
            selectBox.style.height = 0;
        }
    }

    function wordItemStyle(item) {
        const w = mode === 1 ? (item[1] * wordWidth).toString().concat('px') : (item[1] * 100).toString().concat('%');
        return {
            width: w,
            minHeight: item[2].toString().concat('px'),
            border: item[3].concat(' ').concat(item[4]).concat(' ').concat(item[5]),
            backgroundColor: item[6],
            color: item[7],
            fontFamily: item[8],
            fontSize: item[9],
            lineHeight: item[10],
            fontWeight: item[11],
            left: item[12],
            top: item[13],
            position: item[14],
            textAlign: item[15],
            zIndex: item[16],
            margin: item[17],
            padding: item[18]
        }
    }

    function renderTempData(data) {
        container.innerHTML = "";
        childInfos = [];
        valueHandle = {};
        groupInfos = {};
        groupComponents = {};
        dataIndex = 0;
        let temp;
        if (data instanceof Array && data.length > 1) {
            temp = data[0];
            container.style.minHeight = temp[0].toString().concat('px');
            container.style.border = temp[1].concat(' ').concat(temp[2]).concat(" ").concat(temp[3]);
            container.style.backgroundColor = temp[4];
            container.style.color = temp[5];
            container.style.fontFamily = temp[6];
            container.style.fontSize = temp[7];
            container.style.lineHeight = temp[8];
            container.style.fontWeight = temp[9];
            container.style.margin = temp[10];
            container.style.padding = temp[11];
            const { borderWidth, paddingLeft, paddingRight, offsetWidth, width } = window.getComputedStyle(container);
            wordWidth = parseInt(width) - 2 * parseInt(borderWidth) - parseInt(paddingLeft) - parseInt(paddingRight);
            temp = data[1];
            if (temp instanceof Array) {
                temp.forEach(function (item) {
                    addItemByComponent(tableCellType(me, mode, item[0]), wordItemStyle(item));
                });
            }
            itemChange();
        }
    }
    /**
     * 新增一个元素
     * @param {*} component 组件
     * @param {*} style 默认样式
     * @param {*} insertBeforeNode dom元素  往这个元素前面插入新增的元素
     * @param {*} groupIndex 组编号  所属组当中第几个元素集
     * @param {*} value 给新增的元素赋值 类型Object
     * @returns 
     */
    function addItemByComponent(component, style, insertBeforeNode, groupIndex, value) {
        if (component && component.render) {
            const { attrData: { fieldName, groupName } } = component;
            const childNode = component.render();
            if (style instanceof Object) {
                for (var key in style) {
                    childNode.style[key] = style[key];
                }
            }
            if (insertBeforeNode) {
                container.insertBefore(childNode, insertBeforeNode);
            } else {
                container.appendChild(childNode);
            }
            if (component.renderAfter) {
                component.renderAfter();
            }
            if (component.tableInstance) {
                component.tableInstance.selectedCellChange = childNodeSelectedChange;
            }
            const cellInfo = {
                id: idCount,
                component,
                node: childNode,
                info: undefined
            };
            childInfos.push(cellInfo);
            if (mode == 1 && !fieldName) {
                dataIndex += 1;
                component.attrData.fieldName = dataIndex.toString();
            }
            if (groupIndex == undefined) {
                groupIndex = 0;
            }
            if (groupName) {
                if (groupInfos[groupName]) {
                    groupInfos[groupName][groupIndex].push(cellInfo);
                    groupComponents[groupName][groupIndex].push(component);
                } else {
                    groupInfos[groupName] = [[cellInfo]];
                    groupComponents[groupName] = [[component]];
                }
                if (fieldName && component.setValue && value) {
                    component.setValue(value[fieldName]);
                }
            } else if (fieldName && component.getValue && component.setValue) {
                valueHandle[fieldName] = {
                    getValue: component.getValue,
                    setValue: component.setValue
                }
            }
            childNode.info = childInfos[childInfos.length - 1];
            idCount += 1;
        } else {
            console.warn("组件不存在，或者没有实现render函数");
        }
        return idCount - 1;
    }
    function deleteItemById(id) {
        let hasRemove = false;
        const size = childInfos.length - 1;
        for (let i = 0; i < childInfos.length; i += 1) {
            if (id === childInfos[i].id) {
                hasRemove = true;
                container.removeChild(childInfos[i].node);
            }
            if (hasRemove && i < size) {
                childInfos[i] = childInfos[i + 1];
            }
        }
        if (hasRemove) {
            childInfos.pop();
        }
    }

    this.getTemplateData = getTempData;
    this.renderTemplate = renderTempData;

    this.render = function (node, templateData) {
        if (node instanceof Node) {
            parentNode = node;
            node.appendChild(container);
            if ((mode == 1) && node) {
                container.addEventListener('mousedown', onMouseDown, false);
                container.addEventListener('mouseenter', itemChange, false);
                container.addEventListener('mousemove', onMouseMove, false);
                container.addEventListener('mouseup', onMouseUp, false);
            }
        }
        container.innerHTML = "";
        childInfos = [];
        valueHandle = {};
        if (selectBox) {
            container.appendChild(selectBox)
        }
        if (templateData) {
            renderTempData(templateData);
        }
    }
    this.render(node);

    this.getValues = function () {
        const values = {};
        var fun;
        for (let key in valueHandle) {
            fun = valueHandle[key];
            if (fun) {
                values[key] = fun.getValue();
            }
        }
        return values;
    }

    this.getValue = function (fieldName) {
        const fun = valueHandle[fieldName];
        if (fun) {
            return fun.getValue();
        }
        return;
    }

    this.setValues = function (values) {
        if (values instanceof Object) {
            var fun;
            for (let key in values) {
                fun = valueHandle[key];
                if (fun) {
                    fun.setValue(values[key]);
                } else {
                    console.warn("字段[".concat(key).concat("]对应表格中没有相对于的setValue方法，无法赋值！"));
                }
            }
        }
    }

    this.setValue = function (fieldName, value) {
        const fun = valueHandle[fieldName];
        if (fun) {
            fun.setValue(value);
        } else {
            console.warn("字段[".concat(fieldName).concat("]对应表格中没有相对于的setValue方法，无法赋值！"));
        }
    }

    /**
     * 新增一个元素
     * @param {*} attribute 属性
     * @param {*} style 默认样式
     * @returns 
     */
    this.addItemByAttrib = function (attribute, style) {
        if (attribute && attribute.type) {
            const component = tableCellType(me, mode, attribute);
            return addItemByComponent(component, style);
        } else {
            console.warn("传入属性不能为空或者type不能为空");
        }
    }
    /**
     * 删除指定的一个元素
     * @param {*} id 
     */
    this.removeItemById = function (id) { // 作废
        deleteItemById(id);
        itemChange();
    }
    this.removeItemBySelect = function () {
        if (selectItem) {
            deleteItemById(selectItem.id);
            itemChange();
        }
    }
    /**
     * 获取指定元素
     * @param {*} id 
     * @returns 返回元素对象
     */
    this.getItemById = function (id) { // 作废
        const temp = childInfos.find(function (item) {
            return item.id === id;
        });
        if (temp) {
            return temp.component;
        }
        return undefined;
    }
    /**
     * 替换一个元素
     * @param {*} id 
     * @param {*} attribute 
     * @returns 
     */
    this.replaceItemBySelect = function (attribute) {
        if (selectItem && attribute && attribute.type) {
            const component = tableCellType(me, mode, attribute);
            return me.replaceItemByComponent(selectItem.id, component);
        } else {
            console.warn("没有选中单元");
        }
    }
    this.replaceItemByComponent = function (id, component) {
        if (component && component.render) {
            const childNode = component.render();
            for (let i = 0; i < childInfos.length; i += 1) {
                if (id === childInfos[i].id) {
                    container.removeChild(childInfos[i].node);
                    container.appendChild(childNode);
                    childInfos[i] = {
                        id,
                        component,
                        node: childNode,
                        info: getNodeInfo(childNode)
                    };
                    childNode.info = childInfos[i];
                    break;
                }
            }
        } else {
            console.warn("组件不存在，或者没有实现render函数");
        }
        return id;
    }
    this.cellHeightChange = itemChange;
    this.cellChange = itemChange;

    /**
     * 设置单元格样式
     * @param {*} style 
     */
    this.setCellStyle = function (style) {
        let node = selectItem ? selectItem.node : container;
        if (style instanceof Object) {
            for (var key in style) {
                node.style[key] = style[key];
            }
            itemChange();
        }
    }

    /**
     * 高亮组成员单元格 
     * @param {*} groupCells 数组，通过getSelectedCells获取的数据
     */
    this.showGroupCells = function (groupCells) {
        if (groupCells) {
            clearSelectedCells();
            selectedCells = groupCells;
            let className;
            selectedCells.forEach(({ node }) => {
                className = node.getAttribute('class');
                className = className ? className.concat(selectClassName) : selectClassName;
                node.setAttribute('class', className);
            });
        }
    }
    /**
     * 获取传入单元格，获取重新渲染所需数据
     * @param {*} groupCells 单元格，数组，通过getSelectedCells获取
     * @param {*} groupName 组名
     * @returns 
     */
    this.getGroupCellsInfo = function (groupCells, groupName) {
        return groupCells.map(item => {
            item.component.attrData.groupName = groupName;
            return getWordItemData(item);
        })
    }
    this.getSelectedCells = function () {
        return selectedCellsBack;
    }

    /**
     * 根据组名自动查出这一组当中最后一行，并在最后一行添加新的组成员
     * @param {*} groupName 
     * @param {*} addCellInfos 
     * @param {*} value 给新增的单元格赋值 
     */
    this.addCellsByGroupName = function (groupName, addCellInfos, value) {
        const groupArrs = groupInfos[groupName];
        const size = groupArrs.length;
        const lastGroup = groupArrs[size - 1];
        const insertNode = lastGroup[lastGroup.length - 1].node.nextSibling;
        groupInfos[groupName].push([]);
        groupComponents[groupName].push([]);
        addCellInfos.forEach(item => {
            addItemByComponent(tableCellType(me, mode, item[0]), wordItemStyle(item), insertNode, size, value);
        })
        itemChange();
    };
    /**
     * 通过组名删除组成员
     * @param {*} groupName 
     * @param {*} rows 
     */
    this.delCellsByGroupName = function (groupName, rows) {
        const arrs = groupInfos[groupName].pop();
        groupComponents[groupName].pop();
        arrs.forEach((item) => {
            deleteItemById(item.id);
        });
        itemChange();
    };
    this.getGroupComponents = function (groupName) {
        return groupComponents[groupName];
    }
    this.findGroupCells = function (groupName) {
        return groupInfos[groupName];
    }
    return this;
}

export default GkhContainer;